package com.atguigu.gulimall.search.thread;

import java.util.concurrent.*;

/**
 * @Classname ThreadTest
 * @Description TODO
 * @Date 2021/9/8 14:49
 * @Author Anonymous
 */
@SuppressWarnings("all")
public class ThreadTest {
    public static ExecutorService executor = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
//            System.out.println("当前线程" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("运行结果" + i);
//        }, executor);//用我们指定的线程池
//        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程" + Thread.currentThread().getId());
////            int i = 10 / 2;
//            int i = 10 / 0;
//            System.out.println("运行结果" + i);
//            return i;
//            //whenComplete虽然能感受到异常，但是没法修改返回数据
//        }, executor).whenComplete((res, excption) -> {
//            System.out.println("异步任务成功了。。。结果是" + res + ";异常是" + excption);
//        }).exceptionally(throwable -> {
//            return 10;//出现异常之后返回10
//        });
        //方法执行完成后的处理，无论是成功完成还是失败完成
//        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("运行结果" + i);
//            return i;
//        }, executor).handle((res, exception) -> {
//            if (res != null) {//说明有返回结果
//                return res * 2;
//            }
//            if (exception != null) {//如果出现异常
//                return res;
//            }
//            return 0;
//        });
        //第二个任务结束无返回值，因此泛型用void
        /**
         *线程串行化
         * 1）、thenRun：不能获取到上一步的执行结果，无返回值
         * .thenRunAsync(() -> {
         *             System.out.println("任务2启动了。。。");
         *         }, executor);
         * 2)、thenAccept：能接收上一步结果，但是无返回值
         * thenAcceptAsync((res) -> {
         *             System.out.println("任务二启动成功。。。" + res);
         *         },executor);
         * 3）、能接收上一步结果，有返回值
         * */
//        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("运行结果" + i);
//            return i;
//        }, executor).thenApplyAsync((res) -> {
//            System.out.println("任务2启动了。。。" + res);
//            return "Hello" + res;
//        });
//        String s = future1.get();
//        //获取返回值
//        System.out.println("main.......end........" + s);

        /** 两个都完成*/
//        CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
//            System.out.println("任务1线程" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("任务1结束" + i);
//            return i;
//        }, executor);
//
//        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
//            System.out.println("任务2线程" + Thread.currentThread().getId());
//            try {
//                Thread.sleep(3000);
//                System.out.println("任务2结束");
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            return "Hello";
//        }, executor);

        /** 两个任务只要有一个执行完成，我们就执行任务3
         * runAfterEitherAsync:不感知结果，自己也无返回值
         * acceptEitherAsync:能感知结果，但是自己没有返回值
         * applyToEitherAsync:自己感知结果并且自己有返回值
         * */
//        future01.runAfterEitherAsync(future02, () -> {
//            System.out.println("任务3开始之前的结果");
//        }, executor);

//        future01.acceptEitherAsync(future02, t -> {
//            System.out.println("任务3开始之前的结果" + t);
//        }, executor);
//        CompletableFuture<String> future = future01.applyToEitherAsync(future02, (res) -> {
//            System.out.println("任务3开始之前的结果" + res);
//            return res.toString() + "==>哈哈";
//        }, executor);
//        System.out.println("main.......end........" + future.get());

        CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的图片信息");
            return "Hello.jpg";
        }, executor);

        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的属性");
            return "黑色+256";
        }, executor);

        CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);//模拟业务超长
                System.out.println("查询商品的介绍");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "一加666";
        }, executor);

//        futureImg.get();futureAttr.get();futureDesc.get();//假如要等所有异步结束才能往下执行，可以这样等待，但是这是阻塞式等待，不太好
        CompletableFuture<Void> future = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
        future.get();//等待所有结果完成
//        future.join();

        System.out.println("main......end....." + futureImg.get() + "===" + futureAttr.get() + "===" + futureDesc.get());


//        future01.runAfterBothAsync(future02, () -> {
//            System.out.println("任务3开始");
//        },executor);
        //th和u分别表示future01和02的返回值
//        future01.thenAcceptBothAsync(future02, (t, u) -> {
//            System.out.println("任务3开始" + "=======" + t + "=====" + u);
//        }, executor);

//        CompletableFuture<String> future = future02.thenCombineAsync(future01, (f1, f2) -> {
//            return f1 + ":" + f2 + "--Hello";
//        }, executor);
//        //获取返回值
//        System.out.println("main.......end........" + future.get());
    }
    //当前线程12
    //异步任务成功了。。。结果是null;异常是java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
    //main.......end........10


    public void thread(String[] args) {
        System.out.println("main方法。。。。。start...");
        //1）、继承 Thread
//        Thread01 thread01 = new Thread01();
//        thread01.start();//启动线程
        //2）、实现 Runnable 接口
//        Runable01 runable01 = new Runable01();
//        new Thread(runable01).start();
        //3）、实现 Callable 接口 + FutureTask （可以拿到返回结果，可以处理异常）
//        FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
//        new Thread(futureTask).start();
//        try {
//            //阻塞等待整个线程执行完成，拿到返回结果
//            Integer i = futureTask.get();
//            System.out.println(i);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        } catch (ExecutionException e) {
//            e.printStackTrace();
//        }
        //4）、线程池
        //创建：
        //1、Executors
        //2、ThreadPoolExecutor threadPool = new ThreadPoolExecutor();阿里巴巴建议这种原生方式
        //给线程池直接提交任务,如果每次使用原生的比如Runnable开启一个线程，
        // 就如同每次来一个任务公司就招一个员工，资源消耗非常大
        //我们以后在业务代码中，以上三种启动线程的方式都不用，【应该将所有的多线程异步任务交给线程池执行】
//        new Thread(() -> {
//            System.out.println("Hello");
//        });
        //当前系统中池只有一两个，每一个异步任务直接提交给线程池让它执行就行
        //阿里巴巴规范并不支持用下面的方式创建线程池
//        ExecutorService service = Executors.newFixedThreadPool(10);

        Runable01 runable01 = new Runable01();
        runable01.run();
//        service.execute(new Runable01());
//        ThreadPoolExecutor threadPool = new ThreadPoolExecutor();

        System.out.println("main方法。。。。。end...");
    }

    //继承Thread类
    public static class Thread01 extends Thread {
        @Override
        public void run() {
            System.out.println("当前线程" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果" + i);
        }
    }

    //实现runnable接口
    public static class Runable01 implements Runnable {

        @Override
        public void run() {
            System.out.println("当前线程" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果" + i);
        }
    }

    //泛型就是返回结果的类型
    public static class Callable01 implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果" + i);
            return i;
        }
    }
}


